package unused;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import org.newdawn.slick.Image;
import org.newdawn.slick.opengl.ImageIOImageData;

/**
 * Fetches images from the robot's PCVideoServer
 * 
 * @author pmalmsten
 */
public class TCPImageFetcher {
    public static final int MAX_IMG_SIZE_BYTES = 500000;
    public static final int READ_TIMEOUT_MS = 3000;
    public static final int VIDEO_TO_PC_PORT = 1180;
    
    private Socket socket = null;
    private InputStream inputStream = null;
    private byte[] imgBuffer = null;
    private int maxImgBufferSize = 0;
    private ByteArrayInputStream baistream = null;
    private DataInputStream daistream = null;

    /**
     * Creates a new TCPImageFetcher which will attempt to read from the
     * given team's robot
     *
     * @param teamNumber The team number to use
     * @throws UnknownHostException
     * @throws IOException
     */
    public TCPImageFetcher(String ip) throws IOException  {
    	socket = new Socket(InetAddress.getByName(ip), VIDEO_TO_PC_PORT);
        socket.setSoTimeout(READ_TIMEOUT_MS);
        inputStream = socket.getInputStream();
        daistream = new DataInputStream(inputStream);
    }

    /**
     * Reads and returns an image from the associated socket connection. Blocks
     * until a valid image arrives.
     * @return The image received
     */
    public Image fetch() throws IOException {
        byte[] header = new byte[4];
        
        while(true) {
            blockingRead(inputStream, header, 4);

            // Look for header 1,0,0,0
            if(!((header[0] == 1) && ((header[1] + header[2] + header[3]) == 0))) {
                continue;
            }

            // wait for length integer (4 bytes)
            while(inputStream.available() < 4) {}

            // Read int length of data to follow
            int imgDataLen = daistream.readInt();
            //System.out.println(" Data Len: " + imgDataLen + "Hex:" + Integer.toHexString(imgDataLen));

            // Read in the expected number of bytes
            resizeBuffer(imgDataLen);
            blockingRead(inputStream, imgBuffer, imgDataLen);
            baistream.reset();

            // Read the image
            ImageIOImageData data = new ImageIOImageData();
            data.loadImage(baistream);
            return new Image(data);
        }
    }

    /**
     * Ensures that the image buffer byte array is always an appropriate size
     * @param size Requested size for the image buffer
     */
    private void resizeBuffer(int size) {
        if(size > maxImgBufferSize) {
            if(size > MAX_IMG_SIZE_BYTES) size = MAX_IMG_SIZE_BYTES;
            maxImgBufferSize = size + 100;
            imgBuffer = new byte[maxImgBufferSize];
            baistream = new ByteArrayInputStream(imgBuffer);
        }
    }

    /**
     * Guarantees that the requested number of bytes are read from the given
     * input stream and are written to the given buffer before returning.
     * @param istream Stream to read from.
     * @param buf Array to write to.
     * @param requestedBytes Requested number of bytes to read and store.
     * @throws IOException
     */
    private void blockingRead(InputStream istream, byte[] buf, int requestedBytes) throws IOException {
        int offset = 0;
        while(offset < requestedBytes) {
            int read = istream.read(buf, offset, requestedBytes - offset);
            if(read < 0) {
                throw new IOException("Connection interrupted");
            }
            offset += read;
        }
    }
}
